package com.hmdp.utils;

import cn.hutool.core.lang.UUID;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.concurrent.TimeUnit;

/**
 * ClassName: SimpleRedisLock
 * Package: IntelliJ IDEA
 * Description:
 * Written by HanXu
 * Create 2024.09.30 14:36
 */
public class SimpleRedisLock implements ILock{

    private String name;
    private StringRedisTemplate stringRedisTemplate;

    private static final String KEY_PRE = "lock:";
    private static final String ID_PRE = UUID.randomUUID().toString(true)+"-";

    //导入Lua脚本
    private static final DefaultRedisScript<Long> UNLOCK_SCRIPT;

    static {
        UNLOCK_SCRIPT = new DefaultRedisScript<>();
        UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua"));
        UNLOCK_SCRIPT.setResultType(Long.class);
    }

    public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {
        this.name = name;
        this.stringRedisTemplate = stringRedisTemplate;
    }

    @Override
    public boolean tryLock(long timeout) {
        //获取当前线程
        String threadId = ID_PRE + Thread.currentThread().getId();

        //set thread_n NX EX timeout
        Boolean ifLock = stringRedisTemplate.opsForValue()
                .setIfAbsent(KEY_PRE + name, threadId, timeout, TimeUnit.SECONDS);
        //SimpleRedisLock redisLock = new SimpleRedisLock("order:" + userId, stringRedisTemplate);

        //直接返回ifLock会触发自动拆箱，若为null会有空指针风险
        return Boolean.TRUE.equals(ifLock);
    }

    /* 分布式锁方案1
    @Override
    public void unlock() {
        //判断当前锁是否为本线程的锁
        String threadId = ID_PRE +  Thread.currentThread().getId();
        String threadIdString = stringRedisTemplate.opsForValue().get(KEY_PRE + name);

        //判断锁标识和释放锁的两个动作并不具有原子性
        if((threadId).equals(threadIdString)){
            //释放锁
            stringRedisTemplate.delete(KEY_PRE + name);
        }
    }
    */

    /*
    * 分布式锁方案2: Lua脚本
    */
    @Override
    public void unlock() {

        stringRedisTemplate.execute(
                UNLOCK_SCRIPT,
                Collections.singletonList(KEY_PRE + name),
                ID_PRE +  Thread.currentThread().getId());
    }
}
